package aa

import (
	"fmt"
	"syscall"
	"unsafe"

	"golang.org/x/sys/windows"
)

const (
	WS_EX_TOPMOST    uint32 = 0x00000008 // 置顶扩展样式
	WS_EX_TOOLWINDOW uint32 = 0x00000080 // 工具窗口扩展样式
	WS_POPUP         uint32 = 0x80000000 // 弹出窗口样式
	WS_VISIBLE       uint32 = 0x10000000 // 窗口可见样式
	ES_CENTER        uint32 = 0x0008     // 文本居中样式
	ES_READONLY      uint32 = 0x0800     // 文本只读样式

	// 窗口控制常量
	EM_SETMARGINS    uint32 = 0x00C9 // 设置文本边距消息
	SWP_NOMOVE       int32  = 0x0002 // SetWindowPos：不移动
	SWP_NOSIZE       int32  = 0x0001 // SetWindowPos：不改变大小
	SWP_NOZORDER     int32  = 0x0004 // SetWindowPos：不改变Z序
	SWP_FRAMECHANGED int32  = 0x0020 // SetWindowPos：刷新边框
	SW_HIDE          int32  = 0x0000 // ShowWindow：隐藏
	SW_SHOW          int32  = 0x0005 // ShowWindow：显示

	// 窗口句柄常量
	HWND_TOPMOST   = ^uintptr(0) // 置顶Z序（对应 C# IntPtr(-1)）
	HWND_NOTOPMOST = ^uintptr(1) // 取消置顶Z序（对应 C# IntPtr(-2)）

	// 图标配置
	PinHeight int32  = 20  // 图标窗口高度
	PinWidth  int32  = 20  // 图标窗口宽度
	PinText   string = "顶" // 图标显示文本
)

// 结构体定义（完全对齐 C# 的 WINDOWINFO 结构）
// 参考：https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/ns-winuser-windowinfo
type RECT struct {
	Left   int32
	Top    int32
	Right  int32
	Bottom int32
}

type WINDOWINFO struct {
	cbSize          uint32 // 结构大小（必须初始化）
	rcWindow        RECT   // 窗口边框矩形
	rcClient        RECT   // 客户区矩形
	dwStyle         uint32 // 窗口基本样式
	dwExStyle       uint32 // 窗口扩展样式（关键：用于判断 WS_EX_TOPMOST）
	dwWindowStatus  uint32 // 窗口状态
	cxWindowBorders int32  // 窗口边框宽度
	cyWindowBorders int32  // 窗口边框高度
	atomWindowType  uint16 // 窗口类原子
	wCreatorVersion uint16 // 创建者版本
}

type MARGINS struct {
	Left   int32
	Right  int32
	Top    int32
	Bottom int32
}

type WNDPROC func(hwnd uintptr, msg uint32, wParam uintptr, lParam uintptr) uintptr

// Windows API 导入（补充 GetWindowInfo，与 C# 调用逻辑对齐）
var (
	gdi32 = syscall.NewLazyDLL("gdi32.dll")

	// 核心 API：与 C# 参考代码中的函数完全对应
	GetWindowInfo        = user32.NewProc("GetWindowInfo") // 替代原 GetWindowLongPtrW
	SetWindowPos         = user32.NewProc("SetWindowPos")  // 与 C# 一致
	CreateWindowExW      = user32.NewProc("CreateWindowExW")
	SendMessageW         = user32.NewProc("SendMessageW")
	DestroyWindow        = user32.NewProc("DestroyWindow")
	SetWindowLongPtrW    = user32.NewProc("SetWindowLongPtrW")
	CallWindowProcW      = user32.NewProc("CallWindowProcW")
	GetDC                = user32.NewProc("GetDC")
	ReleaseDC            = user32.NewProc("ReleaseDC")
	GetWindowTextLengthW = user32.NewProc("GetWindowTextLengthW")
	GetWindowTextW       = user32.NewProc("GetWindowTextW")
	SetTextColor         = gdi32.NewProc("SetTextColor")
	ShowWindow           = user32.NewProc("ShowWindow")
)

// A窗口 类：封装窗口逻辑
type A窗口 struct {
	A主窗口HWND uintptr // 关联的主窗口句柄（对应 C# 的 IntPtr hWnd）
	图标窗口HWND uintptr // 自身图标窗口句柄
	默认窗口过程   uintptr // 系统默认窗口过程
	上一次位置    RECT    // 主窗口上一次位置
	窗口过程     WNDPROC // 自定义窗口过程
}

// 1. A新建A窗口：创建初始隐藏的图标窗口（不变）
func A新建A窗口(A主窗口HWND uintptr) (*A窗口, error) {
	// 第一步：调用 GetWindowInfo 获取主窗口信息（完全参照 C# 逻辑）
	var 主窗口信息 WINDOWINFO
	主窗口信息.cbSize = uint32(unsafe.Sizeof(主窗口信息)) // 必须初始化大小，否则 API 调用失败
	ret, _, err := GetWindowInfo.Call(
		A主窗口HWND,
		uintptr(unsafe.Pointer(&主窗口信息)),
	)
	if ret == 0 || err != syscall.Errno(0) { // C# 中返回 bool，Go 中返回非0为成功
		return nil, fmt.Errorf("GetWindowInfo 调用失败: %w", err)
	}

	// 第二步：创建图标窗口（初始隐藏）
	图标窗口HWND, 默认窗口过程, err := 创建图标窗口(主窗口信息.rcWindow)
	if err != nil || 图标窗口HWND == 0 {
		return nil, fmt.Errorf("创建图标窗口失败: %w", err)
	}

	// 第三步：返回实例
	return &A窗口{
		A主窗口HWND: A主窗口HWND,
		图标窗口HWND: 图标窗口HWND,
		默认窗口过程:   默认窗口过程,
		上一次位置:    主窗口信息.rcWindow,
		窗口过程:     wndProc,
	}, nil
}

func (a *A窗口) A主窗口是否已置顶() (bool, error) {
	if a.A主窗口HWND == 0 {
		return false, fmt.Errorf("主窗口HWND无效（0）")
	}

	// 第一步：初始化 WINDOWINFO 结构（必须设置 cbSize）
	var 窗口信息 WINDOWINFO
	窗口信息.cbSize = uint32(unsafe.Sizeof(窗口信息))

	// 第二步：调用 GetWindowInfo 获取窗口完整信息
	ret, _, err := GetWindowInfo.Call(
		a.A主窗口HWND,
		uintptr(unsafe.Pointer(&窗口信息)),
	)
	if ret == 0 || err != syscall.Errno(0) {
		return false, fmt.Errorf("获取窗口信息失败: %w", err)
	}

	return (窗口信息.dwExStyle & WS_EX_TOPMOST) != 0, nil
}

func (a *A窗口) A设置窗口置顶() {
	if a.A主窗口HWND == 0 {
		fmt.Println("⚠️ 主窗口HWND无效，无法置顶")
		return
	}

	SetWindowPos.Call(
		a.A主窗口HWND,
		uintptr(HWND_TOPMOST),
		0, 0, 0, 0,
		uintptr(SWP_NOMOVE|SWP_NOSIZE),
	)
}

// 4. A取消窗口置顶：与 C# 逻辑一致，同时隐藏图标
func (a *A窗口) A取消窗口置顶() {
	fmt.Printf("A取消窗口置顶 ing👇\n")
	fmt.Printf("主窗口HWND 👉 %+v\n", a.A主窗口HWND)

	if a.A主窗口HWND == 0 {
		fmt.Println("⚠️ 主窗口HWND无效，无法取消置顶")
		return
	}

	ret, _, err := SetWindowPos.Call(
		a.A主窗口HWND,
		uintptr(HWND_NOTOPMOST),
		0, 0, 0, 0,
		uintptr(SWP_NOMOVE|SWP_NOSIZE),
	)
	if ret == 0 || err != syscall.Errno(0) {
		fmt.Printf("⚠️ 取消置顶失败: %+v\n", err)
	} else {
		// 隐藏图标窗口（扩展逻辑）
		if a.图标窗口HWND != 0 {
			ShowWindow.Call(a.图标窗口HWND, uintptr(SW_HIDE))
			fmt.Printf("✅ 图标窗口已隐藏（HWND: %d）\n", a.图标窗口HWND)
		}
	}
}

func (a *A窗口) A切换窗口置顶() error {
	已置顶, err := a.A主窗口是否已置顶()
	if err != nil {
		return fmt.Errorf("判断窗口状态失败: %w", err)
	}

	if 已置顶 {
		a.A取消窗口置顶()
		fmt.Printf("🔄 已取消置顶: %s (HWND: %d)\n", a.A取主窗口标题(), a.A主窗口HWND)
	} else {
		a.A设置窗口置顶()
		if err := a.A显示图标(); err != nil {
			return fmt.Errorf("显示图标失败: %w", err)
		}
		fmt.Printf("✅ 已置顶: %s (HWND: %d)\n", a.A取主窗口标题(), a.A主窗口HWND)
	}
	return nil
}

func (a *A窗口) A显示图标() error {
	if a.图标窗口HWND == 0 {
		return fmt.Errorf("图标窗口未初始化（HWND=0）")
	}
	_, _, err := ShowWindow.Call(a.图标窗口HWND, uintptr(SW_SHOW))
	if err != syscall.Errno(0) {
		return fmt.Errorf("显示图标失败: %w", err)
	}
	fmt.Printf("✅ 图标窗口已显示（HWND: %d）\n", a.图标窗口HWND)
	return nil
}

func (a *A窗口) A更新图标位置() error {
	var 主窗口信息 WINDOWINFO
	主窗口信息.cbSize = uint32(unsafe.Sizeof(主窗口信息))
	ret, _, err := GetWindowInfo.Call(a.A主窗口HWND, uintptr(unsafe.Pointer(&主窗口信息)))
	if ret == 0 || err != syscall.Errno(0) {
		return err
	}
	当前位置 := 主窗口信息.rcWindow

	if 当前位置 == a.上一次位置 {
		return nil
	}

	新X := 当前位置.Left + (当前位置.Right-当前位置.Left-PinWidth)/2
	新Y := 当前位置.Top - PinHeight
	SetWindowPos.Call(
		a.图标窗口HWND,
		HWND_TOPMOST,
		uintptr(新X),
		uintptr(新Y),
		0, 0,
		uintptr(SWP_NOSIZE|SWP_NOZORDER),
	)

	a.上一次位置 = 当前位置
	return nil
}

func (a *A窗口) A销毁() {
	fmt.Printf("A销毁 ing👇\n")
	if a.图标窗口HWND != 0 {
		a.A取消窗口置顶()
		DestroyWindow.Call(a.图标窗口HWND)
		a.图标窗口HWND = 0
	}
	a.A主窗口HWND = 0
	a.默认窗口过程 = 0
}

func (a *A窗口) A取主窗口标题() string {
	长度, _, _ := GetWindowTextLengthW.Call(a.A主窗口HWND)
	if 长度 == 0 {
		return "无标题窗口"
	}
	buf := make([]uint16, 长度+1)
	GetWindowTextW.Call(a.A主窗口HWND, uintptr(unsafe.Pointer(&buf[0])), uintptr(长度+1))
	return syscall.UTF16ToString(buf)
}

func 创建图标窗口(主窗口位置 RECT) (图标窗口HWND uintptr, 默认窗口过程 uintptr, err error) {
	初始X := 主窗口位置.Left + (主窗口位置.Right-主窗口位置.Left-PinWidth)/2
	初始Y := 主窗口位置.Top - PinHeight

	编辑框类名, err := windows.UTF16PtrFromString("EDIT")
	if err != nil {
		return 0, 0, err
	}
	图标文本, err := windows.UTF16PtrFromString(PinText)
	if err != nil {
		return 0, 0, err
	}

	// 无 WS_VISIBLE，初始隐藏
	窗口样式 := uintptr(WS_POPUP | ES_CENTER | ES_READONLY)
	图标窗口HWND, _, err = CreateWindowExW.Call(
		uintptr(WS_EX_TOPMOST|WS_EX_TOOLWINDOW),
		uintptr(unsafe.Pointer(编辑框类名)),
		uintptr(unsafe.Pointer(图标文本)),
		窗口样式,
		uintptr(初始X),
		uintptr(初始Y),
		uintptr(PinWidth),
		uintptr(PinHeight),
		0, 0, 0, 0,
	)
	if 图标窗口HWND == 0 {
		return 0, 0, err
	}

	// 设置红色文本
	dc, _, _ := GetDC.Call(图标窗口HWND)
	if dc != 0 {
		SetTextColor.Call(dc, uintptr(0x000000FF))
		ReleaseDC.Call(图标窗口HWND, dc)
	}

	// 配置边距
	配置图标边距(图标窗口HWND)

	// 设置自定义窗口过程
	GWLP_WNDPROC := int32(-4)
	默认窗口过程, _, _ = SetWindowLongPtrW.Call(
		图标窗口HWND,
		uintptr(GWLP_WNDPROC),
		uintptr(syscall.NewCallback(wndProc)),
	)

	return 图标窗口HWND, 默认窗口过程, nil
}

func 配置图标边距(图标窗口HWND uintptr) {
	边距 := MARGINS{Left: 5, Right: 5, Top: 5, Bottom: 5}
	SendMessageW.Call(
		图标窗口HWND,
		uintptr(EM_SETMARGINS),
		uintptr(1),
		uintptr(unsafe.Pointer(&边距)),
	)
	SetWindowPos.Call(
		图标窗口HWND,
		HWND_TOPMOST,
		0, 0, 0, 0,
		uintptr(SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED),
	)
}

func wndProc(hwnd uintptr, msg uint32, wParam uintptr, lParam uintptr) uintptr {
	// 拦截激活和鼠标点击，避免抢夺焦点
	if msg == 0x0006 || msg == 0x0201 {
		return 0
	}
	// 转发其他消息
	GWLP_WNDPROC := int32(-4)
	默认过程, _, _ := SetWindowLongPtrW.Call(hwnd, uintptr(GWLP_WNDPROC), 0)
	ret, _, _ := CallWindowProcW.Call(默认过程, uintptr(hwnd), uintptr(msg), wParam, lParam)
	return ret
}
